﻿using System;
using System.Collections.Generic;
using System.Net;
using log4net;
using StockFinder.Model;

namespace StockFinder.YahooFinance
{
    public class YahooFinanceOnlineStockPriceHistoryExtractor : IHistoricDailyPricesExtractor
    {
        private static readonly ILog Log = LogManager.GetLogger(typeof(YahooFinanceOnlineStockPriceHistoryExtractor)); 
        private readonly YahooFinanceOnlineStockPriceHistoryDownloader _Downloader = new YahooFinanceOnlineStockPriceHistoryDownloader();        

        private static readonly char[] DelimiterComma = new[] { ',' };
        private static readonly char[] DelimiterNewline = new[] { '\n' };

        /// <summary>
        /// Attempts to gets up to 40 years worth of historic prices
        /// </summary>
        /// <param name="symbol"></param>
        /// <returns></returns>
        public List<DailyPrice> GetHistoricPrices(Symbol symbol)
        {
            return GetHistoricPrices(symbol, DateTime.Today.AddYears(-40), DateTime.Today);
        }

        public void LoadHistoricPrices(Symbol symbol, DateTime fromDate, DateTime toDate)
        {            
            var pricesCsv = _Downloader.DownloadSymbolPricesCsv(symbol, fromDate, toDate);

            //was the page hit a success?
            if (!string.IsNullOrEmpty(pricesCsv))
            {
                symbol.Prices = ExtractDailyPricesFromSource(pricesCsv);
            }
        }

        public List<DailyPrice> GetHistoricPrices(Symbol symbol, DateTime fromDate, DateTime toDate)
        {
            List<DailyPrice> prices = null;

            var pricesCsv = _Downloader.DownloadSymbolPricesCsv(symbol, fromDate, toDate);

            //was the page hit a success?
            if (!string.IsNullOrEmpty(pricesCsv))
            {
                prices = ExtractDailyPricesFromSource(pricesCsv);
            }

            return prices;
        }

        private static List<DailyPrice> ExtractDailyPricesFromSource(string pageSource)
        {
            if (string.IsNullOrEmpty(pageSource))
            {
                //empty page source
                throw new ArgumentNullException("pageSource", "pageSource can not be null or empty in this context");
            }

            var dailyPrices = new List<DailyPrice>();

            var dailyPriceLines = pageSource.Split(DelimiterNewline);

            //check we have some prices
            if (dailyPriceLines.Length > 1)
            {
                string[] dailyPriceComponents;

                string dailyPriceLine;

                //loop each price line
                for (var dailyPriceLineIndex = 1; dailyPriceLineIndex < dailyPriceLines.Length; dailyPriceLineIndex++)
                {
                    dailyPriceLine = dailyPriceLines[dailyPriceLineIndex];

                    //split up line into price components e.g open, close etc
                    dailyPriceComponents = dailyPriceLine.Split(DelimiterComma);

                    //make sure we have all componets
                    if (dailyPriceComponents.Length == 7)
                    {
                        var priceDate = Convert.ToDateTime(dailyPriceComponents[0]);

                        //add to list
                        dailyPrices.Add(new DailyPrice
                        {
                            PriceDate = priceDate,
                            Open = Convert.ToDecimal(dailyPriceComponents[1]),
                            High = Convert.ToDecimal(dailyPriceComponents[2]),
                            Low = Convert.ToDecimal(dailyPriceComponents[3]),
                            Close = Convert.ToDecimal(dailyPriceComponents[4]),
                            Volume = Convert.ToDecimal(dailyPriceComponents[5]),
                            AdjustedClose = Convert.ToDecimal(dailyPriceComponents[6]),
                        });
                    }
                }

                //**bug in yahoo finance where sometimes it duplicates the latest price**
                if (dailyPrices.Count > 2)
                {
                    var firstPrice = dailyPrices[0];
                    var secondPrice = dailyPrices[1];

                    if (firstPrice.PriceDate == secondPrice.PriceDate)
                    {
                        dailyPrices.RemoveAt(0);

                        Log.WarnFormat("Duplicate price for date - {0}. Removing last entry.", 
                            secondPrice.PriceDate.ToString("dd/MM/yyyy"));
                    }
                }
            }

            return dailyPrices;
        }
    }
}
